﻿using System;
using System.Threading;

namespace Wheels
{
    public abstract class ThreadSafeDisposable
        : IDisposable
    {
#pragma warning disable 1591

        private volatile bool mIsDisposeCalled = false;
        protected bool IsDisposeCalled { get { return mIsDisposeCalled; } }
        private volatile int mIsDisposeFired = 0;
        protected bool IsDisposeFired { get { return mIsDisposeFired != 0; } }
        private volatile bool mIsDisposed = false;
        public bool IsDisposed { get { return mIsDisposed; } }

        protected abstract void Dispose(bool disposing);

        private void DoDispose(bool disposing)
        {
            if (disposing)
                mIsDisposeCalled = true;

#pragma warning disable 0420
            if (Interlocked.CompareExchange(ref mIsDisposeFired, 1, 0) != 0) 
                return;
#pragma warning restore 0420

            Dispose(disposing);

            mIsDisposed = true;
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }

        public void Dispose()
        {
            DoDispose(true);
        }

        ~ThreadSafeDisposable()
        {
            DoDispose(false);
        }
    }
}
